﻿using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;

namespace Faz.SideWinderSC.Client
{
    /// <summary>
    /// Defines a WPF component that registers keyboard inputs.
    /// </summary>
    public class KeyBox : Control
    {
        /// <summary>
        /// Initializes the static elemznts of the <see cref="KeyBox"/> class.
        /// </summary>
        static KeyBox()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(KeyBox), new FrameworkPropertyMetadata(typeof(KeyBox)));
        }

        /// <summary>
        /// Identifies the <see cref="KeyBox.Keys"/> dependency property.
        /// </summary>
        public static readonly DependencyProperty KeysProperty =
            DependencyProperty.Register("Keys", typeof(Key[]), typeof(KeyBox), new PropertyMetadata(new Key[0], OnKeysPropertyChanged));

        /// <summary>
        /// Identifies the <see cref="KeyBox.Key"/> dependency property.
        /// </summary>
        public static readonly DependencyProperty KeyProperty =
            DependencyProperty.Register("Key", typeof(Key), typeof(KeyBox), new PropertyMetadata(Key.None, OnKeyPropertyChanged));

        /// <summary>
        /// Identifies the <see cref="KeyBox.Mode"/> dependency property.
        /// </summary>
        public static readonly DependencyProperty ModeProperty =
            DependencyProperty.Register("Mode", typeof(KeyBoxMode), typeof(KeyBox));

        /// <summary>
        /// Initializes a new instance of the <see cref="KeyBox"/> class.
        /// </summary>
        public KeyBox()
        {
            this.Focusable = true;
        }

        /// <summary>
        /// Gets or sets the associated keys.
        /// </summary>
        public Key[] Keys
        {
            get { return (Key[])this.GetValue(KeysProperty); }
            set { this.SetValue(KeysProperty, value); }
        }

        /// <summary>
        /// Gets or sets the associated key.
        /// </summary>
        public Key Key
        {
            get { return (Key)this.GetValue(KeyProperty); }
            set { this.SetValue(KeyProperty, value); }
        }

        /// <summary>
        /// Gets or sets the mode of the control.
        /// </summary>
        public KeyBoxMode Mode
        {
            get { return (KeyBoxMode)this.GetValue(ModeProperty); }
            set { this.SetValue(ModeProperty, value); }
        }

        /// <summary>
        /// Called when one of the mouse burtons is pressed.
        /// </summary>
        /// <param name="e">The details of the event.</param>
        protected override void OnMouseDown(MouseButtonEventArgs e)
        {
            base.OnMouseDown(e);
            Keyboard.Focus(this);
        }

        /// <summary>
        /// Called when one of the keyboard key is pressed.
        /// </summary>
        /// <param name="e">The details of the event.</param>
        protected override void OnKeyDown(KeyEventArgs e)
        {
            if (e.IsRepeat)
            {
                // Ignore repeated key
                return;
            }

            if (this.Mode == KeyBoxMode.MultiKey)
            {
                var results = new Key[this.Keys.Length + 1];
                Array.Copy(this.Keys, results, this.Keys.Length);
                results[this.Keys.Length] = e.Key;

                this.Keys = results;
            }
            else
            {
                this.Keys = new Key[] { e.Key };
            }
        }

        protected virtual void OnKeysPropertyChanged(DependencyPropertyChangedEventArgs e)
        {
            var values = (Key[])e.NewValue;
            if (values == null || values.Length == 0)
            {
                this.Key = Key.None;
            }
            else
            {
                this.Key = values[0];
            }
        }

        protected virtual void OnKeyPropertyChanged(DependencyPropertyChangedEventArgs e)
        {
            var value = (Key)e.NewValue;
            if (this.Keys == null || this.Keys.Length != 1 || this.Keys[0] != value)
            {
                this.Keys = new Key[] { value };
            }
        }

        private static void OnKeysPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((KeyBox)d).OnKeysPropertyChanged(e);
        }

        private static void OnKeyPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((KeyBox)d).OnKeyPropertyChanged(e);
        }
    }
}
